/* 
 * File:   CUtilities.cpp
 * Author: andrea
 * 
 * Created on November 6, 2013, 7:51 PM
 */

#include "CUtilities.h"
#include <iostream>
#include <dirent.h>
#include "../Headers/includes.h"

using namespace std;
using namespace cv;

CUtilities::CUtilities() {
}

/**
 * Computes the median of a matrixSide*matrixSide matrix, centered in x,y. 
 * @param x
 * @param y
 * @param matrixSide int must be odd
 * @param img Mat BGR encoded
 * @return  Vec3b the median BGR color
 */
cv::Vec3b CUtilities::computeMedianOddBGR(int x, int y, int matrixSide, Mat img) {
    try {
        if (matrixSide % 2 == 0) {
            throw (CUSERR_MATRIX_SIDE_EVEN_EXPEC_ODD);
        }
        int elemNr = matrixSide * matrixSide;
        x = x - (matrixSide - 1) / 2;
        y = y - (matrixSide - 1) / 2;

        if (x < 0 || y < 0) {
            throw (CUSERR_MATRIX_SIDE_EVEN_EXPEC_ODD);
        }

        // arrays used to store the RGB value for each pixel
        int reds[elemNr];
        int greens[elemNr];
        int blues[elemNr];

        int k = 0;
        for (int i = x; i < x + matrixSide; i++) {
            for (int j = y; j < y + matrixSide; j++) {
                reds[k] = img.at<Vec3b>(i, j)[2];
                greens[k] = img.at<Vec3b>(i, j)[1];
                // increment k
                blues[k++] = img.at<Vec3b>(i, j)[0];
            }
        }

        // Sort the arrays to compute median
        sort(reds, reds + elemNr);
        sort(greens, greens + elemNr);
        sort(blues, blues + elemNr);

        int midRed = reds[(elemNr - 1) / 2];
        int midGreen = greens[(elemNr - 1) / 2];
        int midBlue = blues[(elemNr - 1) / 2];
        return Vec3b(midBlue, midGreen, midRed);
    } catch (int e) {
        CErrors err;
        cout << err.getErrorMessage(e) << endl;
    }
}

/**
 * Computes the median of a matrixSide*matrixSide matrix, centered in x,y. 
 * @param x
 * @param y
 * @param matrixSide int must be odd
 * @param img Mat HSV encoded
 * @return  Vec3b the median BGR color
 */
cv::Vec3b CUtilities::computeMedianOddHSV(int x, int y, int matrixSide, Mat img) {
    try {
        if (matrixSide % 2 == 0) {
            throw (CUSERR_MATRIX_SIDE_EVEN_EXPEC_ODD);
        }
        int elemNr = matrixSide * matrixSide;
        x = x - (matrixSide - 1) / 2;
        y = y - (matrixSide - 1) / 2;

        if (x < 0 || y < 0) {
            throw (CUSERR_MATRIX_SIDE_EVEN_EXPEC_ODD);
        }

        // arrays used to store the RGB value for each pixel
        int Hs[elemNr];
        int Ss[elemNr];
        int Vs[elemNr];

        int k = 0;
        for (int i = x; i < x + matrixSide; i++) {
            for (int j = y; j < y + matrixSide; j++) {
                Hs[k] = img.at<Vec3b>(i, j)[0];
                Ss[k] = img.at<Vec3b>(i, j)[1];
                Vs[k++] = img.at<Vec3b>(i, j)[2];
                // increment k
            }
        }

        // Sort the arrays to compute median
        sort(Hs, Hs + elemNr);
        sort(Ss, Ss + elemNr);
        sort(Vs, Vs + elemNr);

        int midH = Hs[(elemNr - 1) / 2];
        int midS = Ss[(elemNr - 1) / 2];
        int midV = Vs[(elemNr - 1) / 2];
        cout << "median: (" << midH << "," << midS << "," << midV << ")" << endl;
        return Vec3b(midH, midS, midV);
    } catch (int e) {
        CErrors err;
        cout << err.getErrorMessage(e) << endl;
    }
}

/**
 * Returns the vector of the filenames inside the directory passed as parameter 
 * (absolute path)
 * @param path char* the path
 * @return vector<string> 
 */
vector<string> CUtilities::getFilesListFromDir(string path) {
    DIR *dir;
    vector<string> files;
    const char* cpath = path.c_str();
    struct dirent *ent;
    if ((dir = opendir(cpath)) != NULL) {
        /* print all the files and directories within directory */
        while ((ent = readdir(dir)) != NULL) {
            string name = ent->d_name;
            if (name != "." && name != ".." ) {
                files.push_back(path + ent->d_name);
            }
        }
        closedir(dir);
    }
    return files;
}